import {ScannerResult} from "../../types";
import path from "path";
import fs from "fs-extra";
import folderSize from "../../utils/folderSize";
import {FormatUtil} from "../../utils/FormatUtil";
import {XmlUtil} from "../../utils/XmlUtil";

// C#包依赖信息
interface CSharpDependency {
  id: string;
  version: string;
  targetFramework?: string;
}

// C#项目类型
enum CSharpProjectType {
  UNKNOWN = "未知",
  CONSOLE = "控制台应用",
  WEB = "Web应用",
  WPF = "WPF应用",
  WINFORMS = "Windows窗体应用",
  CLASS_LIBRARY = "类库",
  ASP_NET = "ASP.NET应用",
  ASP_NET_CORE = "ASP.NET Core应用",
  BLAZOR = "Blazor应用",
  MAUI = ".NET MAUI应用"
}

/**
 * 从csproj项目文件中提取目标框架
 */
function extractTargetFramework(csprojContent: string): string {
  const targetFramework = XmlUtil.getTagValue(csprojContent, 'TargetFramework') || 
                        XmlUtil.getTagValue(csprojContent, 'TargetFrameworks');
  return targetFramework || '未指定';
}

/**
 * 从csproj项目文件中提取SDK类型
 */
function extractSdkType(csprojContent: string): string {
  const projectTagMatch = csprojContent.match(/<Project\s+Sdk="([^"]+)"/);
  return projectTagMatch ? projectTagMatch[1] : '';
}

/**
 * 从csproj项目文件中提取项目类型
 */
function determineProjectType(csprojContent: string, projectPath: string): CSharpProjectType {
  const sdk = extractSdkType(csprojContent);
  const targetFramework = extractTargetFramework(csprojContent).toLowerCase();
  
  // 检查Program.cs文件是否含有特定内容
  const programCsPath = path.join(projectPath, 'Program.cs');
  let programContent = '';
  if (fs.existsSync(programCsPath)) {
    programContent = fs.readFileSync(programCsPath, 'utf-8');
  }
  
  if (csprojContent.includes('<OutputType>Exe</OutputType>') || 
      csprojContent.includes('<OutputType>Exe</OutputType>'.toLowerCase())) {
    return CSharpProjectType.CONSOLE;
  }
  
  if (csprojContent.includes('<OutputType>Library</OutputType>') || 
      csprojContent.includes('<OutputType>Library</OutputType>'.toLowerCase())) {
    return CSharpProjectType.CLASS_LIBRARY;
  }
  
  if (csprojContent.includes('Microsoft.NET.Sdk.Web') || sdk.includes('Microsoft.NET.Sdk.Web')) {
    if (csprojContent.includes('Blazor') || programContent.includes('Blazor')) {
      return CSharpProjectType.BLAZOR;
    }
    if (targetFramework.includes('core')) {
      return CSharpProjectType.ASP_NET_CORE;
    }
    return CSharpProjectType.ASP_NET;
  }
  
  if (csprojContent.includes('Microsoft.NET.Sdk.MAUI') || sdk.includes('Microsoft.NET.Sdk.MAUI')) {
    return CSharpProjectType.MAUI;
  }
  
  if (csprojContent.includes('WindowsPresentationFoundation') || 
      csprojContent.includes('<UseWPF>true</UseWPF>') ||
      programContent.includes('System.Windows')) {
    return CSharpProjectType.WPF;
  }
  
  if (csprojContent.includes('WindowsForms') || 
      csprojContent.includes('<UseWindowsForms>true</UseWindowsForms>') ||
      programContent.includes('System.Windows.Forms')) {
    return CSharpProjectType.WINFORMS;
  }
  
  return CSharpProjectType.UNKNOWN;
}

/**
 * 从packages.config或csproj文件中提取NuGet包依赖
 */
function extractPackageDependencies(content: string, isPackagesConfig: boolean): CSharpDependency[] {
  const dependencies: CSharpDependency[] = [];
  
  if (isPackagesConfig) {
    // packages.config 格式
    const packageRegex = /<package\s+id="([^"]+)"\s+version="([^"]+)"(?:\s+targetFramework="([^"]+)")?/g;
    let match;
    
    while ((match = packageRegex.exec(content)) !== null) {
      dependencies.push({
        id: match[1],
        version: match[2],
        targetFramework: match[3]
      });
    }
  } else {
    // 新的csproj格式
    const packageRegex = /<PackageReference\s+Include="([^"]+)"\s+Version="([^"]+)"/g;
    let match;
    
    while ((match = packageRegex.exec(content)) !== null) {
      dependencies.push({
        id: match[1],
        version: match[2]
      });
    }
  }
  
  return dependencies;
}

/**
 * C#项目扫描器
 */
export async function CSharpScanner(projectPath: string): Promise<ScannerResult | null> {
  try {
    // 查找.csproj文件
    let csprojFiles: string[] = [];
    try {
      const files = await fs.readdir(projectPath);
      csprojFiles = files.filter(file => file.endsWith('.csproj'));
    } catch {
      return null;
    }
    
    if (csprojFiles.length === 0) {
      // 尝试查找.sln文件（解决方案文件）
      const files = await fs.readdir(projectPath);
      if (!files.some(file => file.endsWith('.sln'))) {
        return null;
      }
      
      // 如果只有.sln文件但没有.csproj文件，我们可能在解决方案根目录
      // 在这种情况下，我们使用解决方案根目录的基本信息
      // 注意：通常解决方案下会有多个项目，但此扫描器是针对单个项目的
      const slnFile = files.find(file => file.endsWith('.sln'));
      const slnContent = await fs.readFile(path.join(projectPath, slnFile!), 'utf-8');
      
      // 计算项目大小
      const totalSize = await folderSize.loose(projectPath);
      
      // 尝试提取解决方案名称和项目数量
      const slnName = slnFile!.replace('.sln', '');
      const projectCount = (slnContent.match(/Project\(/g) || []).length;
      
      return {
        projectName: slnName,
        basicInfo: [
          {"名称": slnName},
          {"类型": "C# 解决方案"},
          {"路径": projectPath},
          {"大小": FormatUtil.formatFileSize(totalSize)},
          {"项目数量": projectCount},
        ],
        mores: []
      };
    }
    
    // 使用第一个.csproj文件
    const csprojPath = path.join(projectPath, csprojFiles[0]);
    const csprojContent = await fs.readFile(csprojPath, 'utf-8');
    
    // 计算项目大小
    const totalSize = await folderSize.loose(projectPath);
    
    // 检查bin和obj目录大小
    let binSize = 0;
    let objSize = 0;
    
    if (await fs.pathExists(path.join(projectPath, 'bin'))) {
      binSize = await folderSize.loose(path.join(projectPath, 'bin'));
    }
    
    if (await fs.pathExists(path.join(projectPath, 'obj'))) {
      objSize = await folderSize.loose(path.join(projectPath, 'obj'));
    }
    
    // 提取项目名称
    const projectName = csprojFiles[0].replace('.csproj', '');
    
    // 确定项目类型
    const projectType = determineProjectType(csprojContent, projectPath);
    
    // 提取目标框架
    const targetFramework = extractTargetFramework(csprojContent);
    
    // 提取SDK类型
    const sdkType = extractSdkType(csprojContent);
    
    // 提取包依赖
    let dependencies: CSharpDependency[] = [];
    
    // 检查packages.config文件
    const packagesConfigPath = path.join(projectPath, 'packages.config');
    if (await fs.pathExists(packagesConfigPath)) {
      const packagesContent = await fs.readFile(packagesConfigPath, 'utf-8');
      dependencies = extractPackageDependencies(packagesContent, true);
    } else {
      // 从csproj文件提取依赖
      dependencies = extractPackageDependencies(csprojContent, false);
    }
    
    return {
      projectName,
      basicInfo: [
        {"名称": projectName},
        {"类型": `C# ${projectType}`},
        {"路径": projectPath},
        {"大小": FormatUtil.formatFileSize(totalSize)},
        {"编译输出大小(bin)": FormatUtil.formatFileSize(binSize)},
        {"中间文件大小(obj)": FormatUtil.formatFileSize(objSize)},
        {"目标框架": targetFramework},
        {"SDK类型": sdkType},
        {"依赖数量": dependencies.length},
      ],
      mores: [
        {
          title: "NuGet包依赖",
          type: "table",
          list: dependencies.map(dep => ({
            name: dep.id,
            version: dep.version,
            framework: dep.targetFramework || targetFramework
          }))
        },
        {
          title: "项目文件内容",
          type: "text",
          content: csprojContent,
          list: []
        }
      ]
    };
  } catch (error) {
    console.error(`扫描 C# 项目失败: ${projectPath}`, error);
    return null;
  }
} 